package util

import (
	"fmt"
	"io"
	"os"
	"time"
)

const (
	TAGAPP0 = 0xFFE0
	TAGAPP1 = TAGAPP0 + 1
	TAGAPP2 = TAGAPP0 + 2
	TAGAPP3 = TAGAPP0 + 3
	TAGAPP4 = TAGAPP0 + 4
	TAGAPP5 = TAGAPP0 + 5
	TAGAPP6 = TAGAPP0 + 6
	TAGAPP7 = TAGAPP0 + 7
	TAGAPP8 = TAGAPP0 + 8
	TAGAPP9 = TAGAPP0 + 9
	TAGEXIT = 0x45786966
	//TAGDATETIME 图像最后一次被修改时的日期/时间
	TAGDATETIME = 0x0132
	//TAGDATETIMEORIGINAL 照片在被拍下来的日期/时间
	TAGDATETIMEORIGINAL = 0x9003
	//TAGDATETIMEDIGITIZED 照片被数字化时的日期/时间
	TAGDATETIMEDIGITIZED = 0x9004
)

var TagNameMap map[uint16]string

func init() {
	TagNameMap = make(map[uint16]string)
	InitTag()
}

type EXIFTag struct {
	TagName   uint16
	TagType   uint16
	TagCount  uint32
	TagOffset uint32
	Data      []byte
}

func ReadPhotoExitDateTime(name string) (time.Time, bool) {
	//fmt.Println(name)
	f, _ := os.Open(name)
	defer f.Close()
	for {
		b := BytesToU16BE(readBufFromFile(f, 2))
		switch b {
		case 0xFFD8:
		case TAGAPP0:
			l := BytesToU16BE(readBufFromFile(f, 2))
			readBufFromFile(f, int64(l-2))
		case TAGAPP1: //, TAGAPP2, TAGAPP3, TAGAPP4, TAGAPP5:
			//fmt.Printf("TAGAPP: %X", b)
			l := BytesToU16BE(readBufFromFile(f, 2))
			return decodeEXIF(readBufFromFile(f, int64(l-2)))
		default:
			goto BREAKFOR
		}
	}
BREAKFOR:
	return time.Now(), false
}

func decodeEXIF(buf []byte) (time.Time, bool) {
	index := 0
	if len(buf) < 8 {
		return time.Now(), false
	}
	if BytesToU32BE(buf[index:index+4]) == TAGEXIT {
		index += 4
		index += 2
		switch BytesToU16BE(buf[index : index+2]) {
		case 0x4D4D: //BE
			if BytesToU16BE(buf[index+2:index+4]) == 42 {
				return decodeTag(buf[index:], true)
			}
		case 0x4949: //LE
			if BytesToU16LE(buf[index+2:index+4]) == 42 {
				return decodeTag(buf[index:], false)
			}
		}
	}
	return time.Now(), false
}

func readBufFromFile(f *os.File, len int64) []byte {
	buf := make([]byte, len)
	io.ReadFull(f, buf)
	return buf
}

func decodeIFD(tMap map[uint16]EXIFTag, buf []byte, base int, isBE bool) (int, int) {
	subIFDOffset := 0
	nextIFDOffset := 0
	if len(buf) < int(base+2) {
		return subIFDOffset, nextIFDOffset
	}
	tagCount := BytesToU16(buf[base:base+2], isBE)
	base += 2
	for index := 0; index < int(tagCount); index++ {
		eTag := EXIFTag{}
		eTag.TagName = BytesToU16(buf[base:base+2], isBE)
		base += 2
		eTag.TagType = BytesToU16(buf[base:base+2], isBE)
		base += 2
		eTag.TagCount = BytesToU32(buf[base:base+4], isBE)
		base += 4
		if int(eTag.TagCount) <= 4 {
			eTag.Data = buf[base : base+4]
		} else {
			eTag.TagOffset = BytesToU32(buf[base:base+4], isBE)
			if len(buf) >= int(eTag.TagOffset+eTag.TagCount) {
				eTag.Data = buf[int(eTag.TagOffset):int(eTag.TagOffset+eTag.TagCount)]
			}
		}
		base += 4
		if eTag.TagName == 0x8769 {
			subIFDOffset = int(BytesToU32(eTag.Data, isBE))
		}
		if eTag.TagName == 0xa005 {
			subIFDOffset = int(BytesToU32(eTag.Data, isBE))
		}
		tMap[eTag.TagName] = eTag
	}

	if len(buf) >= int(base+4) {
		nextIFDOffset = int(BytesToU32(buf[base:base+4], isBE))
	}
	return subIFDOffset, nextIFDOffset
}

func decodeTag(buf []byte, isBE bool) (time.Time, bool) {
	//fmt.Println(len(buf))
	tagMap := make(map[uint16]EXIFTag)
	sub, next := decodeIFD(tagMap, buf, 8, isBE)
	if sub > 0 {
		sub, _ = decodeIFD(tagMap, buf, sub, isBE)
		if sub > 0 {
			decodeIFD(tagMap, buf, sub, isBE)
		}
	}
	if next > 0 {
		decodeIFD(tagMap, buf, next, isBE)
	}
	/*for _, v := range tagMap {
		fmt.Println(v.TagName, TagNameMap[v.TagName])
	}*/
	bTime := time.Now()
	hasTime := false
	if v, ok := tagMap[TAGDATETIMEORIGINAL]; ok {
		if t, err := getTime(v.Data); err == nil {
			bTime = t
			hasTime = true
			return bTime, hasTime
		}
	}
	if v, ok := tagMap[TAGDATETIMEDIGITIZED]; ok {
		if t, err := getTime(v.Data); err == nil {
			bTime = t
			hasTime = true
			return bTime, hasTime
		}
	}
	if v, ok := tagMap[TAGDATETIME]; ok {
		if t, err := getTime(v.Data); err == nil {
			bTime = t
			hasTime = true
			return bTime, hasTime
		}
	}
	return bTime, hasTime
}

func getTime(buf []byte) (time.Time, error) {
	blen := len(buf)
	if blen <= 0 {
		return time.Now(), fmt.Errorf("errrrrrrrrr")
	}
	local, _ := time.LoadLocation("Local")
	tt, err := time.ParseInLocation("2006:01:02 15:04:05", string(buf[:blen-1]), local)
	return tt, err
}

// 初始化Tag
func InitTag() {
	//IFD0 (主图像)使用的标签
	TagNameMap[0x010e] = "ImageDescription"      //类型：ascii string；；；；描述：用来描述图像. 双字节的字符码不能使用, 如 中文/韩文/日文.
	TagNameMap[0x010f] = "Make"                  //类型：ascii string；；；；描述：表示数字相机的制造商. 在 Exif 标准中, 这个标签是可选的, 但是在DCF中它是必需的.
	TagNameMap[0x0110] = "Model"                 //类型：ascii string；；；；描述：表示数字相机的模块代码. 在 Exif 标准中, 这个标签是可选的, 但在DCF中它也是必需的.
	TagNameMap[0x0112] = "Orientation"           //类型：unsigned short；；；；描述：当拍照时, 相机相对于场景的方向. 在右边表示的是'0th row' 以及 '0th column' 在视觉位置上的关系.
	TagNameMap[0x011a] = "XResolution"           //类型：unsigned rational；；；；描述：图像的 显示/打印 分辨率. 缺省值是 1/72英寸, 但是它没有意义因为个人PC在 显示/打印 图像的时候不使用这个值.
	TagNameMap[0x011b] = "YResolution"           //类型：unsigned rational；；；；描述：图像的 显示/打印 分辨率. 缺省值是 1/72英寸, 但是它没有意义因为个人PC在 显示/打印 图像的时候不使用这个值.
	TagNameMap[0x0128] = "ResolutionUnit"        //类型：unsigned short；；；；描述：XResolution(0x011a)/YResolution(0x011b)的单位. '1' 表示没有单位, '2' 意味着英寸, '3' 表示厘米. 缺省值是 '2'(英寸).
	TagNameMap[0x0131] = "Software"              //类型：ascii string；；；；描述：显示固件的版本号(数字相机的内部控制软件).
	TagNameMap[TAGDATETIME] = "DateTime"         //类型：ascii string；；；；描述：图像最后一次被修改时的日期/时间. 日期的格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共 20个字节. 如果没有设置时钟或者数字相机没有时钟, 则这个域是用空格来填充. 通常, 它和DateTimeOriginal(0x9003)具有相同的值
	TagNameMap[0x013e] = "WhitePoint"            //类型：unsigned rational；；；；描述：定义图像白点(white point/白点：在彩色分色、照相或摄影时作为色彩平衡测量用途的参考点) 的色度(chromaticity). 如果图像是用CIE标准照度 D65(著名的是 '光线/daylight'的国际标准), 这个值是 '3127/10000,3290/10000'.
	TagNameMap[0x013f] = "PrimaryChromaticities" //类型：unsigned rational；；；；描述：定义图像的原始色度. 如果图像使用 CCIR 推荐 709原始色度, 则这个值是 '640/1000,330/1000,300/1000,600/1000,150/1000,0/1000'.
	TagNameMap[0x0211] = "YCbCrCoefficients"     //类型：unsigned rational；；；；描述：当图像的格式是 YCbCr(JPEG的格式), 这个值表示转换成 RGB格式的一个常量. 通常, 这个值是'0.299/0.587/0.114'.
	TagNameMap[0x0213] = "YCbCrPositioning"      //类型：unsigned short；；；；描述：当图像的格式是 YCbCr 并且使用 '子采样/Subsampling'(色度数据的剪切值, 所有的数字相机都使用), 定义了subsampling 像素阵列的色度采样点. '1'表示像素阵列的中心, '2' 表示基准点.
	TagNameMap[0x0214] = "ReferenceBlackWhite"   //类型：unsigned rational；；；；描述：表示黑点(black point)/白点 的参考值. 在YCbCr 格式中,前两个值是 Y的黑点/白点, 下两个值是 Cb, 最后两个值是 Cr. 而在 RGB 格式中, 前两个表示R的黑点/白点, 下两个是 G, 最后两个是 B.
	TagNameMap[0x8298] = "Copyright"             //类型：ascii string；；；；描述：表示版权信息
	TagNameMap[0x8769] = "ExifOffset"            //类型：unsigned long；；；；描述：Exif 子IFD的偏移量
	//Exif 子IFD使用的标签
	TagNameMap[0x829a] = "ExposureTime"                    //类型：unsigned rational；；；；描述：曝光时间 (快门速度的倒数). 单位是秒.
	TagNameMap[0x829d] = "FNumber"                         //类型：unsigned rational；；；；描述：拍照时的光圈F-number(F-stop).
	TagNameMap[0x8822] = "ExposureProgram"                 //类型：unsigned short；；；；描述：拍照时相机使用的曝光程序. '1' 表示手动曝光, '2' 表示正常程序曝光, '3' 表示光圈优先曝光, '4' 表示快门优先曝光, '5' 表示创意程序(慢速程序), '6' 表示动作程序(高速程序), '7'表示 肖像模式, '8' 表示风景模式.
	TagNameMap[0x8827] = "ISOSpeedRatings"                 //类型：unsigned short；；；；描述：CCD 的感光度, 等效于 Ag-Hr 胶片的速率.
	TagNameMap[0x9000] = "ExifVersion"                     //类型：undefined；；；；描述：Exif 的版本号. 用4个ASCII字符来存储. 如果图片是基于Exif V2.1的, 这个值是 "0210". 因为它不是一个用NULL(0x00)来终结的字符串，所以这里的类型是 'undefined'.
	TagNameMap[TAGDATETIMEORIGINAL] = "DateTimeOriginal"   //类型：ascii string；；；；描述：照片在被拍下来的日期/时间. 使用用户的软件是不能被修改这个值的. 日期的格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共占用20个字节. 如果数字相机没有设置时钟或者 数字相机没有时钟, 这个域使用空格来填充. 在Exif标准中, 这个标签是可选的, 但是在 DCF中是必需的.
	TagNameMap[TAGDATETIMEDIGITIZED] = "DateTimeDigitized" //类型：ascii string；；；；描述：照片被数字化时的日期/时间. 通常, 它与DateTimeOriginal(0x9003)具有相同的值. 数据格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共占用20个字节. 如果数字相机没有设置时钟或者 数字相机没有时钟, 这个域使用空格来填充. 在Exif标准中, 这个标签是可选的, 但是在 DCF中是必需的.
	TagNameMap[0x9101] = "ComponentsConfiguration"         //类型：undefined；；；；描述：表示的是像素数据的顺序. 大多数情况下RGB格式使用 '0x04,0x05,0x06,0x00' 而YCbCr 格式使用 '0x01,0x02,0x03,0x00'. 0x00:并不存在, 其他的对应关系为 0x01:Y, 0x02:Cb, 0x03:Cr, 0x04:Red, 0x05:Green, 0x06:Bllue.
	TagNameMap[0x9102] = "CompressedBitsPerPixel"          //类型：unsigned rational；；；；描述：JPEG (粗略的估计)的平均压缩率.
	TagNameMap[0x9201] = "ShutterSpeedValue"               //类型：signed rational；；；；描述：用APEX表示出的快门速度. 为了转换成原始的 'Shutter Speed'; 则先要计算2的ShutterSpeedValue次幂, 然后求倒数. 例如, 如果 ShutterSpeedValue 是 '4', 快门速度则是1/(2 4 )=1/16秒.
	TagNameMap[0x9202] = "ApertureValue"                   //类型：unsigned rational；；；；描述：拍照时镜头的光圈. 单位是 APEX. 为了转换成普通的 F-number(F-stop), 则要先计算出根号2 2 (=1.4142)的ApertureValue次幂. 例如, 如果ApertureValue 是 '5', F-number 就等于1.4142 5 = F5.6.
	TagNameMap[0x9203] = "BrightnessValue"                 /*类型：signed rational；；；；描述：被拍摄对象的明度, 单位是 APEX. 为了从BrigtnessValue(Bv)计算出曝光量(Ev), 你必须加上 SensitivityValue(Sv).
	Ev=Bv+Sv    Sv=log 2 (ISOSpeedRating/3.125)
	ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.*/
	TagNameMap[0x9204] = "ExposureBiasValue" //类型：signed rational；；；；描述：照片拍摄时的曝光补偿. 单位是APEX(EV).
	TagNameMap[0x9205] = "MaxApertureValue"  //类型：unsigned rational；；；；描述：镜头的最大光圈值. 你可以通过计算根号2的MaxApertureValue次幂来转换成普通的光圈 F-number (跟ApertureValue:0x9202的处理过程一样).
	TagNameMap[0x9206] = "SubjectDistance"   //类型：signed rational；；；；描述：到焦点的距离, 单位是米.
	TagNameMap[0x9207] = "MeteringMode"      //类型：unsigned short；；；；描述：曝光的测光方法. '0' 表示未知, '1' 为平均测光, '2' 为中央重点测光, '3' 是点测光, '4' 是多点测光, '5' 是多区域测光, '6' 部分测光, '255' 则是其他.
	TagNameMap[0x9208] = "LightSource"       //类型：unsigned short；；；；描述：光源, 实际上是表示白平衡设置. '0' 意味着未知, '1'是日光, '2'是荧光灯, '3' 白炽灯(钨丝), '10' 闪光灯, '17' 标准光A, '18' 标准光B, '19' 标准光C, '20' D55, '21' D65, '22' D75, '255' 为其他.
	TagNameMap[0x9209] = "Flash"             //类型：unsigned short；；；；描述：'0' 表示闪光灯没有闪光, '1' 表示闪光灯闪光, '5' 表示闪光但没有检测反射光, '7' 表示闪光且检测了反射光.
	TagNameMap[0x920a] = "FocalLength"       //类型：unsigned rational；；；；描述：拍摄照片时的镜头的焦距长度. 单位是毫米.
	TagNameMap[0x927c] = "MakerNote"         //类型：undefined；；；；描述：制造商的内部数据. 一些制造商如 Olympus/Nikon/Sanyo 等在这个区域中使用IFD 格式的数据.
	TagNameMap[0x9286] = "UserComment"       /*类型：undefined；；；；描述：存储用户的注释. 这个标签允许使用两字节的德字符或者 unicode. 前8 个字节描述的是字符集. 'JIS' 是日文 (著名的有 Kanji).
	'0x41,0x53,0x43,0x49,0x49,0x00,0x00,0x00':ASCII
	'0x4a,0x49,0x53,0x00,0x00,0x00,0x00,0x00':JIS
	'0x55,0x4e,0x49,0x43,0x4f,0x44,0x45,0x00':Unicode
	'0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00':Undefined */
	TagNameMap[0x9290] = "SubsecTime"                 //类型：ascii string；；；；描述：一些数字相机每秒能拍摄 2~30 张照片, 但是DateTime/DateTimeOriginal/DateTimeDigitized 标签只能记录到秒单位的时间. SubsecTime 标签就是用来记录秒后面的数据(微秒). 例如, DateTimeOriginal = "1996:09:01 09:15:30", SubSecTimeOriginal = "130", 合并起来的原始的拍摄 时间就是 "1996:09:01 09:15:30.130"
	TagNameMap[0x9291] = "SubsecTimeOriginal"         //类型：ascii string；；；；描述：一些数字相机每秒能拍摄 2~30 张照片, 但是DateTime/DateTimeOriginal/DateTimeDigitized 标签只能记录到秒单位的时间. SubsecTime 标签就是用来记录秒后面的数据(微秒). 例如, DateTimeOriginal = "1996:09:01 09:15:30", SubSecTimeOriginal = "130", 合并起来的原始的拍摄 时间就是 "1996:09:01 09:15:30.130"
	TagNameMap[0x9292] = "SubsecTimeDigitized"        //类型：ascii string；；；；描述：一些数字相机每秒能拍摄 2~30 张照片, 但是DateTime/DateTimeOriginal/DateTimeDigitized 标签只能记录到秒单位的时间. SubsecTime 标签就是用来记录秒后面的数据(微秒). 例如, DateTimeOriginal = "1996:09:01 09:15:30", SubSecTimeOriginal = "130", 合并起来的原始的拍摄 时间就是 "1996:09:01 09:15:30.130"
	TagNameMap[0xa000] = "FlashPixVersion"            //类型：undefined；；；；描述：存储FlashPix 的版本信息. 如果图像数据是基于 FlashPix formar Ver.1.0, 则这个值为 "0100". 因为它不是一个用NULL(0x00)来终结的字符串，所以这里的类型是 'undefined'.
	TagNameMap[0xa001] = "ColorSpace"                 //类型：unsigned short；；；；描述：定义色彩空间. DCF 图像必须使用 sRGB 色彩空间因此这个值总是 '1'. 如果这个照片使用了 其他的色彩空间, 这个值是 '65535':未校准(Uncalibrated).
	TagNameMap[0xa002] = "ExifImageWidth"             //类型：unsigned short/long；；；；描述：主图像的尺寸大小.
	TagNameMap[0xa003] = "ExifImageHeight"            //类型：unsigned short/long；；；；描述：主图像的尺寸大小.
	TagNameMap[0xa004] = "RelatedSoundFile"           //类型：ascii string；；；；描述：如果数字相机能够纪录图像的音频数据, 则表示音频数据的名字.
	TagNameMap[0xa005] = "ExifInteroperabilityOffset" //类型：unsigned long；；；；描述：表示这是一个扩展"ExifR98", 细节未知. 这个值经常是IFD格式的数据. 当前这儿有两个 目录项, 第一个是 Tag0x0001, 值是"R98", 下一个是 Tag0x0002, 它的值为 "0100".
	TagNameMap[0xa20e] = "FocalPlaneXResolution"      //类型：unsigned rational；；；；描述：表示CCD的像素密度. 如果你的相机是百万像素的并且是用低分辨率(如VGA模式) 来拍摄照片, 这个值可以通过照片的分辨率来重新采样. 在这种情况下, FocalPlaneResolution 就不是CCD的实际的分辨率.
	TagNameMap[0xa20f] = "FocalPlaneYResolution"      //类型：unsigned rational；；；；描述：表示CCD的像素密度. 如果你的相机是百万像素的并且是用低分辨率(如VGA模式) 来拍摄照片, 这个值可以通过照片的分辨率来重新采样. 在这种情况下, FocalPlaneResolution 就不是CCD的实际的分辨率.
	TagNameMap[0xa210] = "FocalPlaneResolutionUnit"   //类型：unsigned short；；；；描述：FocalPlaneXResoluton/FocalPlaneYResolution的单位. '1' 表示没有单位, '2'是英寸inch, '3' 表示厘米. 注 意:一些Fujifilm的数码相机(如.FX2700,FX2900,Finepix4700Z/40i 等) 使用的值是 '3' 所以它的单位一定是 '厘米' , 但是它们的分辨率单位就变成'8.3mm?'(1/3in.?). 这是Fuji 的 BUG? 从Finepix4900Z 开始这个值就使用 '2' 了但仍然跟实际的值不吻合.
	TagNameMap[0xa215] = "ExposureIndex"              //类型：unsigned rational；；；；描述：跟ISOSpeedRatings(0x8827)一样但是数据类型是 unsigned rational. 只有Kodak的数字相机使用 这个标签来替代 ISOSpeedRating, 我不知道这是为什么(历史原因?).
	TagNameMap[0xa217] = "SensingMethod"              //类型：unsigned short；；；；描述：表示图像传感器单元的类型. '2' 意味着这是一个芯片颜色区域传感器, 几乎所有的数字相机都 使用这个类型.
	TagNameMap[0xa300] = "FileSource"                 //类型：undefined；；；；描述：显示图像来源. 值 '0x03' 表示图像源是数字定格相机.
	TagNameMap[0xa301] = "SceneType"                  //类型：undefined；；；；描述：表示拍摄场景的类型. 值 '0x01' 表示图像是通过相机直接拍摄出来的.
	TagNameMap[0xa302] = "CFAPattern"                 //类型：undefined；；；；描述：表示色彩过滤阵列(CFA) 几何模式.
	//Interoperability IFD使用的标签
	TagNameMap[0x0001] = "InteroperabilityIndex"   //类型：Ascii string；；；；描述：如果这个IFD 是主图像的 IFD 并且文件内容采用的是 ExifR98 v1.0, 那这个值就是 "R98". 如果是所略图的, 这个值则是 "THM".
	TagNameMap[0x0002] = "InteroperabilityVersion" //类型：Undefined；；；；描述：纪录interoperability的版本. "0100" 表示版本1.00.
	TagNameMap[0x1000] = "RelatedImageFileFormat"  //类型：Ascii string；；；；描述：纪录图像文件的文件格式. 这个值是 ascii 字符串(如. "Exif JPEG Ver. 2.1").
	TagNameMap[0x1001] = "RelatedImageWidth"       //类型：Short or Long；；；；描述：纪录图像的大小尺寸.
	TagNameMap[0x1001] = "RelatedImageLength"      //类型：Short or Long；；；；描述：纪录图像的大小尺寸.
	//IFD1 (缩略图)使用的标签
	TagNameMap[0x0100] = "ImageWidth"                //类型：unsigned short/long；；；；描述：表示缩略图的大小.
	TagNameMap[0x0101] = "ImageLength"               //类型：unsigned short/long；；；；描述：表示缩略图的大小.
	TagNameMap[0x0102] = "BitsPerSample"             //类型：unsigned short；；；；描述：当图像格式没有经过压缩, 这个值表示每像素的比特位的数目. 通常这个值是 '8,8,8'
	TagNameMap[0x0103] = "Compression"               //类型：unsigned short；；；；描述：代表压缩的方式. '1' 表示非压缩, '6' 表示JPEG 压缩格式.
	TagNameMap[0x0106] = "PhotometricInterpretation" //类型：unsigned short；；；；描述：表示图像数据组件的色彩空间. '1' 意味着单色, '2'表示 RGB, '6' 表示 YCbCr.
	TagNameMap[0x0111] = "StripOffsets"              //类型：unsigned short/long；；；；描述：如果图像格式没有经过压缩, 这个值表示的是到图像数据的偏移量. 在图像数据被分割的 情况下它有多个值.
	TagNameMap[0x0115] = "SamplesPerPixel"           //类型：unsigned short；；；；描述：如果图像格式没有经过压缩, 这个值表示每个像素中存储的组件数目. 在彩色图像中, 此值为 '3'.
	TagNameMap[0x0116] = "RowsPerStrip"              //类型：unsigned short/long；；；；描述：如果图像格式没有经过压缩 并且 图像被分割存储, 这个值表示每条数据带存储了多少行数据 . 如果图像没有被分割, 它与ImageLength(0x0101)同值.
	TagNameMap[0x0117] = "StripByteConunts"          //类型：unsigned short/long；；；；描述：如果图像格式没有经过压缩 并且 图像被分割存储, 这个值表示每条数据带使用了多少字节的 数据 且 有多个值. 如果图像没有被分割, 它只有一个且表示为图像的所有数据的大小.
	TagNameMap[0x011a] = "XResolution"               //类型：unsigned rational；；；；描述：图像的显示/打印分辨率. 很多的数字相机都使用1/72英寸的规格, 但对于个人PC 来讲这个值没有任何意义因为在显示/打印的时候不使用这个值.
	TagNameMap[0x011b] = "YResolution"               //类型：unsigned rational；；；；描述：图像的显示/打印分辨率. 很多的数字相机都使用1/72英寸的规格, 但对于个人PC 来讲这个值没有任何意义因为在显示/打印的时候不使用这个值.
	TagNameMap[0x011c] = "PlanarConfiguration"       //类型：unsigned short；；；；描述：如果图像格式是非压缩YCbCr的, 这个值表示YCbCr数据的字节对齐顺序. '1', 表示Y/Cb/Cr值是一个 chunky format, 对于每个子采样像素都是连续的. '2', 则表示Y/Cb/Cr 值被分割存储在 Y plane/Cb plane/Cr plane 格式中.
	TagNameMap[0x0128] = "ResolutionUnit"            //类型：unsigned short；；；；描述：XResolution(0x011a)/YResolution(0x011b)的单位. '1' 表示英寸, '2' 表示厘米.
	TagNameMap[0x0201] = "JpegIFOffset"              //类型：unsigned long；；；；描述：当图像格式是JPEG时, 这个值表示到 JPEG 数据的偏移量.
	TagNameMap[0x0202] = "JpegIFByteCount"           //类型：unsigned long；；；；描述：当图像格式是JPEG时, 表示JPEG 图像的数据大小.
	TagNameMap[0x0211] = "YCbCrCoefficients"         //类型：unsigned rational；；；；描述：当图像格式是YCbCr时, 它表示转换成RGB格式的一个常量值. 通常是'0.299/0.587/0.114'.
	TagNameMap[0x0212] = "YCbCrSubSampling"          //类型：unsigned short；；；；描述：当图像格式是YCbCr时 并且 使用子采样(色度数据的剪切值, 所有的数字相机都使用)时, 这个值表示有多少个色度数据被采样了. 首先第一个值表示水平的, 下一个值表示垂直的 采样率.
	TagNameMap[0x0213] = "YCbCrPositioning"          //类型：unsigned short；；；；描述：当图像格式是YCbCr时 并且 使用子采样(色度数据的剪切值, 所有的数字相机都使用)时, 这个值定义了被采样的像素阵列的色度采样点. '1' 表示像素阵列的中心, '2' 表示基准点(0,0).
	TagNameMap[0x0214] = "ReferenceBlackWhite"       //类型：unsigned rational；；；；描述：表示黑点/白点的参考值. 在 YCbCr 格式的情况下, 前两个表示了Y的黑/白, 下两个是 Cb, 最后两个是 Cr. 在 RGB 的情况下, 前两个表示R的黑/白, 下两个是 G, 最后两个是 B.

}
